package com.example.springmvc.controller;

import com.example.springmvc.model.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.util.UUID;

@Slf4j
// 获取用户请求参数
@Controller
@ResponseBody
@RequestMapping("/user")
public class UserController {

    //传递单个参数
    @RequestMapping("/getuserbyid")
    public User getUSer(Integer id) {
        User user = new User();
        user.setId(id==null? 0: id);
        user.setUsername("zhans");
        user.setAge(12);
        return user;
    }
    // 这里通过fiddler抓包 可以知道返回的是一个json格式的数据 为什么呢?
    //这是因为Spring Boot/Spring MVC的项目
    //会根据我们返回的数据类型来决定设置一个什么 类型更合适。
    //这里我们返回的是一个对象，对象里面有属性值，这就是一个很明显的键值对格式、
    //所以，它返回的是一个JSON 格式的数据。
    //还有一种也是返回JSON 格式的数据: HashMap这个键值对结构
    //如果想前面一样，返回字符串  那么它的类型就是文本类型(Text)



    // 传递多个参数 (非对象)
    @RequestMapping("/echo")
    public String echo(Integer username, String password) {
        return "username:" + username + " password:" + password;
    }
    //但是目前这个代码存在很大的问题就是参数一旦增加。我们就得手动去添加，还可能漏掉某个参数维护的时候，
    //也很难看清楚代码，参数太多了！维护性极低 所以我们使用获取对象




    // 传递多个参数 (对象)
    @RequestMapping("/getuser")
    public String getUser(User user) {
        return "用户信息:" + user;
    }

    //@RequestParam("name")的作用是 前端传的数据可能和后端不一样
    //如 前name 后username 那么后端就接收不到数据了
    //所以 我们可以通过@RequestParam("name")后端参数重命名
    //前端后端不变 后端接收到之后 将其参数名称的数值 赋值到后端的username上
    //但是  如果映射方法是一个对象 那就不能使用RequestParam
    //这里的username是对象里面的属性话 那就不能使用了

    @RequestMapping("/getname")
    public String getName(@RequestParam("name") String username) {
        return username;
    }



    //注意我们查看源码可知道boolean required() default true;是true
    //导致前端必须传一个name的参数 如果不传就会报错 但是我们并不希望这样
    //所以我们在使用时可以修改关键字 这样即使不传name 也不会报错
    @RequestMapping("/getname2")
    public String getName2(@RequestParam(value = "name",required = false) String username) {
        return "用户名:" + username;  //用户名:null
    }



    //注意如果我们映射方法接下来收到的数据是一个json格式的数据
    //那么我们要加上注解@RequestBody  来接收






    //获取URL中参数@PathVariable
    @RequestMapping("/getdata/{id}/{name}")
    public String getData(@PathVariable Integer id, @PathVariable String name) {
        return "id:" + id + " name:" + name;
    }







    //上传文件(图片) @RequestPart
    @RequestMapping("/getimg")
    public Boolean getImg(Integer id, @RequestPart("img") MultipartFile file) {
        //保存图片到本地目录(工作中就是服务器，别人把图片提到我服务器上存储)
        //承载对象是 MultipartFile file 提供的transferTo 方法的参数 将对象存储到指定位置
        //transferTo要求是一个File对象  所以我们需要先new File对象
        //将存储路径作为其参数 同时存储的过程是可能会失败的，因此它会出现异常，我们使用try catch 判断
        //我们使用postman来验证
        boolean result = false;
        try {
            file.transferTo(new File("D:\\BigDataST\\img.png"));// 注意这里要写保存路径和保存名称
            //但是也会造成问题 存储路径被写死了 如果客服端又发送一张图片 那么原本的图片就会被覆盖
            //我们要解决3个问题  1.文件名不能重复 2.存储目录(配置文件) 3.上传图片的个数png,jpg
            result = true;
        } catch (Exception e) {
            log.error("上传图片失败" + e.getMessage());
        }
        return result;
    }
//    1.存储图片名称问题
//      通过时间戳是不可行的  当有人在同一时间存储的时候就会出现问题
//      UUID全局唯一标识符√   UUID.randomUUID()
//    2.保存路径通过配置文件来解决
//    3.上传文件的格式
//      其实MultipartFile对象中，提供了一个API (getOriginalFilename) 。
//      getOriginalFilename:获取原始的文件名称
//      名称里面都有文件后缀,截取文件后缀,就可以获取到文件的格式了


    // 保存的地址
    @Value("${img.path}")//不是lombok的 @Value  该注入要在方法外面
    private String imgPath;
    @RequestMapping("/newgetImg")
    public Boolean newGetImg(Integer id, @RequestPart("img") MultipartFile file) {
        boolean result = false;//判断是否保存成功
        //给图片命名
        String fileName = file.getOriginalFilename();
        fileName = fileName.substring(fileName.lastIndexOf("."));
        fileName = UUID.randomUUID().toString() + fileName;
        try {
            file.transferTo(new File(imgPath + fileName));
            result = true;
        } catch (Exception e) {
            log.error("上传图片失败" + e.getMessage());
        }
        return result;
    }






    //获取Request和Response对象
    //因为 Spring MVC 就是 基于 Servlet API 来实现的
    //Servlet 那一套 是 完全适用于 Spring MVC 的。
    //在 Spring MVC 里面，每一个方法都有2个 “隐藏参数”
    //HttpServletRequest 和 HttpServletResponse  我们写上也不会报错
    @RequestMapping("gethttp")
    public String getHttp(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse){
        return "用户名:" + httpServletRequest.getParameter("name");
        //http://127.0.0.1:8080/user/gethttp
        //用户名:null
        //http://127.0.0.1:8080/user/gethttp?name=asd
        //用户名:asd

        //所以spring mvc支持 servlet API
    }






    //获取cookie,Session,header

    //  获取cookie
    //1.基于servlet提供的API来获取cookie
    @RequestMapping("/getcookie")
    public void getCookie(HttpServletRequest request) {
        // 获取全部的Cookie
        Cookie[] cookies = request.getCookies();
        // 打印cookies  但是我们之间使用浏览器获取到的cookie可能为null 会发生空指针异常
        for (Cookie item : cookies) {
            // 这里我们通过日志来打印cookie  cookie也是通过键值对来存储的  所以我们通过浏览器自己创建几个cookie
            log.info("CookieName:" + item.getName() + " CookieValue:" + item.getValue());
        }
    }
    //2.通过@Cookies注解 获取
    @RequestMapping("/getcookie2")
    public String getCookie2(@CookieValue("name") String value) {
        return "CookieValue:" + value;
    }




    //获取header(获取请求头中的信息)  因为信息很多我们拿Connection举例
    // 1.基于servlet提供的API来获取
    @RequestMapping("/gethead")
    public String getHead(HttpServletRequest request) {
        return "请求头Connection信息: " + request.getHeader("Connection");
        //打印结果
        //请求头Connection信息: keep-alive
    }
    //2.通过@RequestHeader注解获取
    @RequestMapping("/gethead2")
    public String getHead2(@RequestHeader("User-Agent") String head) {
        return "请求头User-Agent信息: " + head;
        //打印结果:
        //请求头User-Agent信息: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.203
    }




    //3. 存储和获取session
    // 关于存储操作 我们只能使用servlet API 因为存储操作没办法用API来表示
    @RequestMapping("/setsession")
    public boolean setSession(HttpServletRequest request) {
        boolean result = false;
        // 1.先获取到HttpSession对象 获取对象时参数必须为true
        // 因为getSession()默认是false  true的意思是 如果会话不存在就创建一个
        HttpSession session = request.getSession(true);
        // 2.使用
        session.setAttribute("user",123);
        result = true;
        return result;
    }

    // 获取session
    @RequestMapping("/getsession")
    public String getSession2(@SessionAttribute(value = "user", required = false) String str) {
        return "user:" + str;
        //required = false和前面的 required = false意思一样
        //注意我们查看源码可知道boolean required() default true;是true
        //导致前端必须传一个user的参数 如果不传就会报错 但是我们并不希望这样
        //所以我们在使用时可以修改关键字 这样即使不传name 也不会报错

        //打印结果
        //user:123  因为我们设置了会话对象 如果没有设置的话那么返回的是null
    }
}
